﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using MongoDB.Bson;
using MongoDB.Driver;
using MongoDB.Driver.Builders;
using eCommMongo.Core.Data;
using eCommMongo.Core.Domain.Pictures;
using eCommMongo.Core.Domain.Products;
using eCommMongo.Core.Domain.Shops;
using eCommMongo.Service.Pictures;

namespace eCommMongo.Service.Products
{
    public class ProductService:IProductService
    {
        private IMongoRepository<Product> _productRepository;
        private IMongoRepository<ProductVariant> _productVariantRepository;
        private IMongoRepository<ProductAttribute> _productAttributeRepository;
        private IMongoRepository<ProductVariantAttribute> _productVariantAttributeRepository;
        private IMongoRepository<ProductVariantAttributeValue> _productVariantAttributeValueRepository;
        private IMongoRepository<SpecificationAttribute> _spRepository;
        private IMongoRepository<SpecificationAttributeOption> _spOptionRepository;
        private IMongoRepository<Picture> _picRepository;
        private IMongoRepository<ProductPicture> _productPictureRepository;
        private IPictureService _pictureService;

        public ProductService(IMongoRepository<Product> productRepository, IMongoRepository<ProductVariant> productVariantRepository, IMongoRepository<ProductAttribute> productAttributeRepository, IMongoRepository<ProductVariantAttribute> productVariantAttributeRepository, IMongoRepository<ProductVariantAttributeValue> productVariantAttributeValueRepository, IMongoRepository<SpecificationAttribute> spRepository, IMongoRepository<SpecificationAttributeOption> spOptionRepository, IMongoRepository<Picture> picRepository, IMongoRepository<ProductPicture> productPictureRepository, IPictureService pictureService)
        {
            _productRepository = productRepository;
            _productVariantRepository = productVariantRepository;
            _productAttributeRepository = productAttributeRepository;
            _productVariantAttributeRepository = productVariantAttributeRepository;
            _productVariantAttributeValueRepository = productVariantAttributeValueRepository;
            _spRepository = spRepository;
            _spOptionRepository = spOptionRepository;
            _picRepository = picRepository;
            _productPictureRepository = productPictureRepository;
            _pictureService = pictureService;
        }

        public void DeleteProduct(Product product)
        {
            throw new System.NotImplementedException();
        }
         
        public IList<Product> GetAllProducts()
        {
            throw new System.NotImplementedException();
        }

        public IList<Product> GetAllProductsByShopPid(string shopId)
        {

            var query = from s in _productRepository.Table()
                        where s.Shop.Id==shopId 
                        select s;

            var p = query.ToList();
            if (p != null)
            {

                return ProductMapper.ToProducts(p);
            }
            else
            {
                return null;
            }
        }

        public void DeleteProduct(string productId)
        {
            var query = from s in _productRepository.Table()
                        where s.Id == productId
                        select s;

            var p = query.SingleOrDefault();
            if (p != null)
            {

                p.Deleted = true;

            }
        }

        public Product GetProductById(string productId)
        {
            var query = from s in _productRepository.Table()
                        where s.Id ==productId
                        select s;

            var p = query.SingleOrDefault();
            if (p != null)
            {

                return ProductMapper.ToProduct(p);
            }
            else
            {
                return null;
            }

        }

     

        public void InsertProduct(Product product)
        {
            throw new System.NotImplementedException();
        }

        public void UpdateProduct(Product product)
        {
            throw new System.NotImplementedException();
        }

        public ProductInfoInsertResult InsertProductInfo(ProductInfoInsertRequest productInfoInsertRequest)
        {
            var result = new ProductInfoInsertResult();

            try
            {
                var p = new Product();
                p.Shop = new Shop() {Id = productInfoInsertRequest.ShopId};
                p.ProductName = productInfoInsertRequest.ProductName;
                p.ShortDescription = GetShortDescription(productInfoInsertRequest);
                p.FullDescription = productInfoInsertRequest.FullDescription;
                p.Published = productInfoInsertRequest.IsPublished;
                p.Deleted = false;
                p.CreatedOnUtc = DateTime.Now;
                p.UpdatedOnUtc = DateTime.Now;
                p.ProductPictures = new List<ProductPicture>()
                    {
                        new ProductPicture()
                            {
                               Picture = new Picture(){Id = productInfoInsertRequest.PictureIds[0]}
                            }
                    };


                p.ProductVariants =new Collection<ProductVariant>();
                _productRepository.Insert(p);

                var pv = new ProductVariant();
                pv.Id = new ObjectId().ToString();
                pv.ShopId = productInfoInsertRequest.ShopId;
                pv.Picture = new Picture() {Id = productInfoInsertRequest.PictureIds[0]};
                pv.Published = productInfoInsertRequest.IsPublished;
                pv.DisplayOrder = 1;
                pv.StockQuantity = productInfoInsertRequest.StockQuantity;
                pv.Price = productInfoInsertRequest.Price;
                pv.CreatedOn = DateTime.Now;
                pv.UpdatedOn= DateTime.Now;
                pv.ProductId = p.Id;


                var update = Update<Product>.Push(c => c.ProductVariants, pv);

                _productRepository.Update(p.Id, update);

                result.Id = p.Id;

            }
            catch (Exception e)
            {
                result.AddError(e.Message);
            }
            return result;
        }

        private string GetShortDescription(ProductInfoInsertRequest productInfoInsertRequest)
        {
            if (!string.IsNullOrEmpty(productInfoInsertRequest.ShortDescription))
            {
                return productInfoInsertRequest.ShortDescription;
            }
            else
            {
                var length = 150;
                if (productInfoInsertRequest.FullDescription.Length > length)
                {
                    return productInfoInsertRequest.FullDescription.Substring(0, length);
                }
                else
                {
                    return productInfoInsertRequest.FullDescription;
                }
            }
        }

        public ProductInfoUpdateResult UpdateProductInfo(ProductInfoUpdateRequest productInfoUpdateRequest)
        {
            var result = new ProductInfoUpdateResult();

            try
            {

                var p = _productRepository.GetById(productInfoUpdateRequest.Id);
                if (p == null)
                {
                    throw new Exception("product not exist");
                }

                p.ProductName = productInfoUpdateRequest.ProductName;
                p.ShortDescription = productInfoUpdateRequest.ShortDescription;
                p.FullDescription = productInfoUpdateRequest.FullDescription;
                p.Published = productInfoUpdateRequest.IsPublished;

                var update = Update<Product>.Set(e => e.ProductName, productInfoUpdateRequest.ProductName)
                                            .Set(e=>e.ShortDescription, productInfoUpdateRequest.ShortDescription)
                                            .Set(e=>e.FullDescription, productInfoUpdateRequest.FullDescription)
                                            .Set(e=>e.Published, productInfoUpdateRequest.IsPublished);

                _productRepository.Update( productInfoUpdateRequest.Id, update);
           
            }
            catch (Exception e)
            {
                result.AddError(e.Message);
            } 
            return result;
        }

        public ProductVariant GetProductVariantById(string productVariantId)
        {
            var query = (from c in _productRepository.Table()
                         where c.ProductVariants.Any(v => v.Id == productVariantId)
                         select c);

            var p = query.SingleOrDefault();
            if (p != null)
            {

                var pvQuery= from pv in p.ProductVariants
                          where pv.Id ==productVariantId
                          select pv;
                var pvobj = pvQuery.SingleOrDefault();
                return pvobj;
            }

            return null;
            ////var query = from s in _productVariantRepository.Table
            ////            where s.Id == productVariantId
            ////            select s;

            //var p = query.SingleOrDefault();
            //if (p != null)
            //{

            //    return ProductMapper.ToProductVariant(p);
            //}
            //else
            //{
            //    return null;
            //}
        }

       

        public ProductVariant GetProductVariantBySku(string sku)
        {
            throw new System.NotImplementedException();
        }

        public string InsertProductVariantInfo(string productId, 
            string name, 
            string sku, 
            decimal price, 
            int displayOrder, 
            int stockQuantity, 
            string pictureId,
            bool published)
        {
            var pv = new ProductVariant()
                {
                    Id = ObjectId.GenerateNewId().ToString(),
                    Name = name,
                    Sku = sku,
                    Price = price,
                    DisplayOrder = displayOrder,
                    StockQuantity = stockQuantity,
                    Picture = _pictureService.GetPictureById(pictureId),
                    Published = published,
                    CreatedOn = DateTime.Now,
                    UpdatedOn = DateTime.Now,
                };

            var update = Update<Product>.Push(e => e.ProductVariants, pv);
            _productVariantRepository.Update( productId, update);
            return pv.Id.ToString();

        }

        public void UpdateProductVariantInfo(string productVariantId, 
            string name,
            string sku, 
            decimal price,
            int displayOrder,
            int stockQuantity, 
            string pictureId,
            bool published)
        {
           
            var update = Update.Set("ProductVariants.$.Name", name)
                               .Set("ProductVariants.$.Sku", sku)
                               .Set("ProductVariants.$.Price",BsonValue.Create(price))
                               .Set("ProductVariants.$.DisplayOrder", displayOrder)
                               .Set("ProductVariants.$.StockQuantity", stockQuantity)
                               .Set("ProductVariants.$.Published", published);
            var query = new QueryDocument { { "ProductVariants._id", new ObjectId(productVariantId) } };

            _productRepository.Update( query,update);

        }

        public void InsertProductVariant(ProductVariant productVariant)
        {
            throw new System.NotImplementedException();
        }

        

        public IList<ProductVariant> GetProductVariantsByProductId(string productId)
        {
            throw new System.NotImplementedException();
        }

        public void DeleteProductVariant(ProductVariant productVariant)
        {
            throw new System.NotImplementedException();
        }

        public void AdjustInventory(ProductVariant productVariant, bool decrease, int quantity, string attributesXml)
        {
            if (productVariant == null)
                throw new ArgumentNullException("productVariant");


            int newStockQuantity = 0;
            if (decrease)
                newStockQuantity = productVariant.StockQuantity - quantity;
            else
                newStockQuantity = productVariant.StockQuantity + quantity;




            UpdateProductVariantStockQuantity(productVariant.Id, newStockQuantity);
        }

        private void UpdateProductVariantStockQuantity(string productVariantId, int stockQuantity)
        {
           

            var update = Update.Set("ProductVariants.$.StockQuantity", stockQuantity);
            var query = new QueryDocument { { "ProductVariants._id", new ObjectId(productVariantId) } };

            _productRepository.Update( query, update);

        }

        public IList<ProductAttribute> GetAllProductAttributes()
        {
            return _productAttributeRepository.Table().ToList();
        }

        public string InsertProductVariantAttribute(string pvId, AttributeControlType selectedAttributeType, int selectedProductAttributeId)
        {

            var pva = new ProductVariantAttribute()
                {
                    Id =ObjectId.GenerateNewId().ToString()
                };
            var update = Update.Push("ProductVariants.$.ProductVariantAttributes", BsonValue.Create(pva));

            var query = new QueryDocument { { "ProductVariants._id", new ObjectId(pvId) } };


            _productRepository.Update( query, update);

            return pva.Id;

        }

        public IList<SpecificationAttribute> GetAllSpecificationAttribute()
        {
            var query = _spRepository.Table();

            var p = query.ToList();
            return p;
        }


        public void InsertProductSpecificationAttribute(string productId, string specificationAttributeOptionId)
        {
            var speficiationAttributeOption= _spOptionRepository.GetById(specificationAttributeOptionId);
            var update = Update<Product>.Push(e => e.ProductSpecificationAttributes,speficiationAttributeOption);
            _productRepository.Update(productId, update);
        }

        public string InsertProductPicture(string productId, string pictureId, int displayOrder)
        {
            
            var picture = _pictureService.GetPictureById(pictureId);
            var product = _productRepository.GetById(productId);
            var maxDisplayOrder = product.ProductPictures.Max(c => c.DisplayOrder) + 1;

            var pp = new ProductPicture()
                {
                    Id = ObjectId.GenerateNewId().ToString(),
                    DisplayOrder = maxDisplayOrder,
                    Picture = picture,
                };

            var update = Update<Product>.Push(e => e.ProductPictures, pp);

            _productRepository.Update( productId, update);
            

            return pp.Id;

        }

        public IList<ProductVariantAttribute> GetProductVariantAttributesByProductVariantId(string productVariantId)
        {
            var pv = this.GetProductVariantById(productVariantId);
            if (pv != null)
            {
                return pv.ProductVariantAttributes.ToList();
            }

            else
            {
                throw  new Exception(string.Format("product variant id: {0} not exist", productVariantId));
            }

        }

        public ProductVariantAttribute GetProductVariantAttributeByProductVariantAttributeId(string productVariantAttributeId)
        {

            


            //var pva =  _productVariantAttributeRepository.GetById(productVariantAttributeId);

            //if (pva != null)
            //{
            //    return new ProductVariantAttribute()
            //        {
            //            ProductVariantId = pva.ProductVariantId,
            //            ProductAttribute = new ProductAttribute()
            //                {
            //                    Name = pva.ProductAttribute.Name
            //                },

            //            ProductVariantAttributeValues =
            //                pva.ProductVariantAttributeValues == null
            //                    ? new List<ProductVariantAttributeValue>()
            //                    : pva.ProductVariantAttributeValues.Select(t => new ProductVariantAttributeValue()
            //                        {
            //                            Name = t.Name,
            //                            DisplayOrder = t.DisplayOrder
            //                        }).OrderBy(c=>c.DisplayOrder).ToList()
            //        };
            //}
            return null;
        }

        public int InsertProductVariantAttributeValue(string productVariantAttributeId, string productVariantAttributeValue, int displayOrder)
        {
            return 0;
            //var pvav = new ProductVariantAttributeValue()
            //    {
            //        DisplayOrder = displayOrder,
            //        Name = productVariantAttributeValue,
            //        ProductVariantAttributeId = productVariantAttributeId
            //    };
            //_productVariantAttributeValueRepository.Insert(pvav);
            //return pvav.Id;
        }

        public ProductVariantAttributeValue GetProductVariantAttributeValueByProductVariantAttributeValueId(
            string productVariantAttributeValueId)
        {

            //var query = from pv in _productVariantAttributeValueRepository.Table
            //            where pv.Id == productVariantAttributeValueId
            //            select pv;

            //var p = query.SingleOrDefault();
            //if (p != null)
            //{
            //    return new ProductVariantAttributeValue()
            //        {
            //            Id = p.Id,
            //            Name = p.Name,
            //            ProductVariantAttribute = new ProductVariantAttribute()
            //                {
            //                    ProductAttribute = new ProductAttribute()
            //                        {
            //                            Name = p.ProductVariantAttribute.ProductAttribute.Name
            //                        }
            //                }

            //        };
            //}

            return null;

        }

        public void DeleteProductVaraintAttribute(string productvariantattributeId)
        {
            //var query = from pv in _productVariantAttributeRepository.Table
            //            where pv.Id == productvariantattributeId
            //            select pv;

            //var p = query.SingleOrDefault();
            //if (p != null)
            //{
            //    _productVariantAttributeRepository.Delete(p);
            //}
        }

        public void DeleteProductVaraint(string productVariantId)
        {
            //var query = from p in _productVariantRepository.Table
            //            where p.Id == productVariantId
            //            select p;

            //var pv = query.SingleOrDefault();
            //if (pv != null)
            //{

            //    var product = pv.Product;
            //    if (product != null)
            //    {
            //        if (product.ProductVariants.Count > 1)
            //        {
            //            pv.Deleted = true;
            //            _productVariantRepository.Update(pv);
            //        }
            //        else
            //        {
            //            throw  new Exception("could not delete last product variant");
            //        }
            //    }
            //}

        }

        public void DeleteProductVaraintAttributeValue(string productvariantattributeValueId)
        {
            //var query = from pva in _productVariantAttributeValueRepository.Table
            //            where pva.Id == productvariantattributeValueId
            //            select pva;

            //var result = query.SingleOrDefault();
            //if (result != null)
            //{
            //    _productVariantAttributeValueRepository.Delete(result);
            //}
        }

        public void DeleteProductPicture(string productPictureId)
        {
            //var query = from pp in _productPictureRepository.Table
            //            where pp.Id == productPictureId
            //            select pp;
            //var pobject = query.SingleOrDefault();
            //if (pobject != null)
            //{
            //    _productPictureRepository.Delete(pobject);
            //}
        }
    }
}